package com.share.config;

import com.share.filter.CustomAuthorizationFilter;
import com.share.filter.CustomLoginAbstractAuthenticationProcessingFilter;
import com.share.handler.CustomLoginAuthenticationFailureHandler;
import com.share.handler.CustomLoginAuthenticationSuccessHandler;
import com.share.handler.CustomNoPermissionsAccessDeniedHandler;
import com.share.handler.CustomUserNotLoginAuthenticationEntryPoint;
import com.share.order.config.CustomUserAuthorizationManager;
import com.share.properties.Whitelist;
import com.share.utils.CryptoUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.firewall.DefaultHttpFirewall;
import org.springframework.security.web.firewall.HttpFirewall;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

@Configuration
public class SecurityDefaultConfig {

    private final AuthenticationManager authenticationManager;
    private final CustomLoginAuthenticationSuccessHandler loginAuthenticationSuccessHandler;
    private final CustomLoginAuthenticationFailureHandler loginAuthenticationFailureHandler;
    private final CustomNoPermissionsAccessDeniedHandler noPermissionsAccessDeniedHandler;
    private final CustomUserNotLoginAuthenticationEntryPoint userNotLoginAuthenticationEntryPoint;
    private final CustomAuthorizationFilter customAuthorizationFilter;
    private final CustomUserAuthorizationManager customUserAuthorizationManager;
    private final Whitelist whitelist;
    private final CryptoUtils cryptoUtils;

    public SecurityDefaultConfig(AuthenticationManager authenticationManager, CustomLoginAuthenticationSuccessHandler loginAuthenticationSuccessHandler, CustomLoginAuthenticationFailureHandler loginAuthenticationFailureHandler, CustomNoPermissionsAccessDeniedHandler noPermissionsAccessDeniedHandler, CustomUserNotLoginAuthenticationEntryPoint userNotLoginAuthenticationEntryPoint, CustomAuthorizationFilter customAuthorizationFilter, CustomUserAuthorizationManager customUserAuthorizationManager, Whitelist whitelist, CryptoUtils cryptoUtils) {
        this.authenticationManager = authenticationManager;
        this.loginAuthenticationSuccessHandler = loginAuthenticationSuccessHandler;
        this.loginAuthenticationFailureHandler = loginAuthenticationFailureHandler;
        this.noPermissionsAccessDeniedHandler = noPermissionsAccessDeniedHandler;
        this.userNotLoginAuthenticationEntryPoint = userNotLoginAuthenticationEntryPoint;
        this.customAuthorizationFilter = customAuthorizationFilter;
        this.customUserAuthorizationManager = customUserAuthorizationManager;
        this.whitelist = whitelist;
        this.cryptoUtils = cryptoUtils;
    }

    @Bean
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
        CustomLoginAbstractAuthenticationProcessingFilter filter = getFilter(http);
        http
                //配置无状态请求
                .sessionManagement(session ->
                        session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(authorize -> authorize
                        .requestMatchers(whitelist.getExcludeList().stream()
                                .map(AntPathRequestMatcher::new)
                                .toArray(AntPathRequestMatcher[]::new))
                        .permitAll()
                        .anyRequest()
                        .authenticated()
                )
                //配置登陆失败的返回处理器
                //配置登陆失败的返回处理器
                .formLogin(configurer -> configurer
                        .failureHandler(loginAuthenticationFailureHandler)
                        .successHandler(loginAuthenticationSuccessHandler)
                )
                // 禁用basic明文验证
                .httpBasic(AbstractHttpConfigurer::disable)
                // 禁用默认登录页
                .formLogin(AbstractHttpConfigurer::disable)
                // 禁用默认登出页
                .logout(AbstractHttpConfigurer::disable)
                //将处理器放在验证之前
                .addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(customAuthorizationFilter, UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(customAuthorizationFilter, ExceptionTranslationFilter.class)
                //配置异常处理
                .exceptionHandling(configurer ->
                        configurer.accessDeniedHandler(noPermissionsAccessDeniedHandler)
                                .authenticationEntryPoint(userNotLoginAuthenticationEntryPoint)
                );
        http
                // 禁用 csrf
                .csrf(AbstractHttpConfigurer::disable)
                .cors(AbstractHttpConfigurer::disable);
        return http.build();
    }

    /**
     * 获取拦截器配置
     *
     * @param http
     * @return
     */
    private CustomLoginAbstractAuthenticationProcessingFilter getFilter(HttpSecurity http) {
        CustomLoginAbstractAuthenticationProcessingFilter filter =
                new CustomLoginAbstractAuthenticationProcessingFilter(authenticationManager, cryptoUtils);
        filter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
        //认证成功处理器
        filter.setAuthenticationSuccessHandler(loginAuthenticationSuccessHandler);
        //认证失败处理器
        filter.setAuthenticationFailureHandler(loginAuthenticationFailureHandler);
        return filter;
    }


    /**
     * 处理特殊文件
     *
     * @return 降低因放宽 URL 编码斜杠限制带来的安全隐患
     */
    @Bean
    public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
        DefaultHttpFirewall firewall = new DefaultHttpFirewall();
        firewall.setAllowUrlEncodedSlash(true);
        return firewall;
    }



}